package redis

import (
	"encoding/json"
	"github.com/edgexfoundry/edgex-go/internal/app/models"
	"github.com/edgexfoundry/edgex-go/internal/app/pkg/controller/http"
	"github.com/edgexfoundry/edgex-go/internal/app/pkg/utils"
	"github.com/edgexfoundry/go-mod-core-contracts/v2/common"
	"github.com/edgexfoundry/go-mod-core-contracts/v2/errors"
	"github.com/gomodule/redigo/redis"
	"time"
)

const (
	AutoEventCollection       = DeviceCollection + DBKeySeparator + AutoEvent
	AutoEventDeviceCollection = DeviceCollection + DBKeySeparator + AutoEvent + DBKeySeparator + common.Device
)

// autoEventsGetByDeviceId AutoEvent get by device id
func autoEventsGetByDeviceId(conn redis.Conn, deviceId string) ([]models.AutoEvent, errors.EdgeX) {
	storedKey := CreateKey(AutoEventDeviceCollection, deviceId)
	objects, edgeXerr := getObjectsByRevRange(conn, storedKey, 0, -1)
	if edgeXerr != nil {
		return nil, errors.NewCommonEdgeXWrapper(edgeXerr)
	}

	autoEvents := make([]models.AutoEvent, len(objects))
	for index, obj := range objects {
		var event models.AutoEvent
		err := json.Unmarshal(obj, &event)
		if err != nil {
			continue
		}

		if event.SourceType == 1 {
			resource, _ := deviceCommandGetByCode(conn, deviceId, event.SourceCode)
			event.SourceName = resource.Name
		} else {
			resource, _ := deviceResourceGetByCode(conn, deviceId, event.SourceCode)
			event.SourceName = resource.Name
		}

		autoEvents[index] = event
	}
	return autoEvents, nil
}

// autoEventAdd 添加自动采集
func autoEventAdd(conn redis.Conn, deviceId string, events ...models.AutoEvent) (err errors.EdgeX) {
	deviceAutoEventKey := CreateKey(AutoEventDeviceCollection, deviceId)

	for _, autoEvent := range events {
		if autoEvent.SourceType == 1 {
			err = checkDeviceCommandExist(conn, deviceId, autoEvent.Id)
		} else {
			err = checkDeviceResourceExist(conn, deviceId, autoEvent.Id)
		}
		if err != nil {
			return
		}
	}
	_ = conn.Send(MULTI)
	for _, autoEvent := range events {

		if autoEvent.Id == "" {
			autoEvent.Id, _ = utils.GenerateUUID()
		}
		s, errJson := json.Marshal(autoEvent)
		if errJson != nil {
			return errors.NewCommonEdgeX(errors.KindServerError, http.ParamsError, errJson)
		}
		autoEventKey := CreateKey(AutoEventCollection, autoEvent.Id)
		_ = conn.Send(SET, autoEventKey, s)
		_ = conn.Send(ZADD, deviceAutoEventKey, time.Now().UnixMilli(), autoEventKey)
	}
	_ = conn.Send(EXEC)
	return nil
}

// autoEventDelete auto event delete
func autoEventDelete(conn redis.Conn, deviceId string, keys ...string) errors.EdgeX {
	deviceAutoEventKey := CreateKey(AutoEventDeviceCollection, deviceId)
	_ = conn.Send(MULTI)
	for _, autoEventKey := range keys {
		_ = conn.Send(DEL, autoEventKey)
		_ = conn.Send(ZREM, deviceAutoEventKey, autoEventKey)
	}
	_ = conn.Send(EXEC)
	return nil
}

// autoEventAdd 自动采集update
func autoEventUpdate(conn redis.Conn, deviceId string, event models.AutoEvent) errors.EdgeX {

	origin, err := autoEventGetById(conn, event.Id)
	if err != nil {
		return err
	}
	origin.Interval = event.Interval
	origin.OnChange = event.OnChange
	origin.SourceCode = event.SourceCode
	origin.SourceName = event.SourceName

	deviceAutoEventKey := CreateKey(AutoEventDeviceCollection, deviceId)
	_ = conn.Send(MULTI)

	s, errJson := json.Marshal(origin)
	if errJson != nil {
		return errors.NewCommonEdgeX(errors.KindServerError, http.ParamsError, errJson)
	}
	autoEventKey := CreateKey(AutoEventCollection, event.Id)
	_ = conn.Send(SET, autoEventKey, s)
	_ = conn.Send(ZADD, deviceAutoEventKey, time.Now().UnixMilli(), autoEventKey)
	_ = conn.Send(EXEC)
	return nil
}

// autoEventExist 自动采集事件是否存在
func autoEventExist(conn redis.Conn, eventId string) (bool, errors.EdgeX) {
	return objectIdExists(conn, CreateKey(AutoEventCollection, eventId))
}

// autoEventGetById 根据id查询自动采集
func autoEventGetById(conn redis.Conn, eventId string) (models.AutoEvent, errors.EdgeX) {
	var event models.AutoEvent
	err := getObjectById(conn, CreateKey(AutoEventCollection, eventId), &event)
	if err != nil {
		return event, err
	}
	return event, nil
}

func deleteAllAutoEventByDeviceId(conn redis.Conn, deviceId string) errors.EdgeX {

	storedKey := CreateKey(AutoEventDeviceCollection, deviceId)
	ids, _ := fieldsByZSet(conn, storedKey)
	return autoEventDelete(conn, deviceId, ids...)
}
